/**
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
** \file DistanceVector.cpp
** \version $Id: DistanceVector.cpp 22 2009-10-28 02:03:29Z rigdern $
*/

#include "DistanceVector.h"

#include <limits.h>

CombinatorialIterator::CombinatorialIterator() 
: _mode(FINISHED)
{
}

CombinatorialIterator::CombinatorialIterator(unsigned int height, 
					    const DistanceVector& maximalVector)
: _currentVector(maximalVector.size(), UINT_MAX),
  _currentElt(_currentVector.begin()),
  _currentHeight(height),
  _lastAttr(maximalVector.size()-1),
  _pos(0)
{
  DistanceVector::const_iterator it;
  unsigned int i, vecSize;
 
  vecSize = maximalVector.size();
  _maximalElements = new unsigned int[vecSize];
  _cutoffs = new unsigned int[vecSize];
  
  for (i = 0, it = maximalVector.begin(); it != maximalVector.end(); ++i, ++it)
    _maximalElements[i] = *it;
  
  if (vecSize == 0) {
    _mode = FINISHED;
  } else if (vecSize == 1) {
    if (_currentHeight <= _maximalElements[0]) {
      _mode = SINGLE_ATTRIBUTE;
      *_currentElt = _currentHeight;
    } else {
      _mode = FINISHED;
    }
  } else {
    _mode = MULTI_ATTRIBUTE;
    ++(*this);
  }
}

CombinatorialIterator::~CombinatorialIterator()
{
  delete[] _maximalElements;
  delete[] _cutoffs;
}

bool
CombinatorialIterator::operator==(const CombinatorialIterator& other)
{
  if (_mode == FINISHED && other._mode == FINISHED)
    return true;

  return _currentVector == other._currentVector;
}

bool
CombinatorialIterator::operator!=(const CombinatorialIterator& other)
{
  return !(*this == other);
}

CombinatorialIterator&
CombinatorialIterator::operator++()
{
  switch (_mode) {
    case MULTI_ATTRIBUTE:
      incrementMultiAttributeVector();
      break;
    case SINGLE_ATTRIBUTE:
      _mode = FINISHED;
      break;
    case FINISHED:
      /* This case is to get rid of a compiler warning. */
      break;
  }
  
  return *this;
}

CombinatorialIterator&
CombinatorialIterator::operator++(int)
{
  return *this;
}

const DistanceVector&
CombinatorialIterator::operator*() const
{
  return _currentVector;
}

const DistanceVector*
CombinatorialIterator::operator->() const
{
  return &_currentVector;
}

void
CombinatorialIterator::incrementMultiAttributeVector()
{
  while (true) {
    if (_pos == _lastAttr) {
      if (_currentHeight <= _maximalElements[_pos]) {
        *_currentElt = _currentHeight;
        --_currentElt;
        --_pos;
        return;
      }
      --_currentElt;
      --_pos;
    } else {
      if (*_currentElt == UINT_MAX) {
        _cutoffs[_pos] = std::min(_currentHeight, _maximalElements[_pos]);
      }
      if ((*_currentElt)++ == _cutoffs[_pos]) {
        _currentHeight += _cutoffs[_pos];
        *_currentElt = UINT_MAX;
        if (_pos == 0) {
          _mode = FINISHED;
          return;
        }
        --_currentElt;
        --_pos;
      } else {
        if (*_currentElt > 0) --_currentHeight;
        ++_currentElt;
        ++_pos;
      }
    }
  }
}
